#!/usr/bin/env node

const { run, test, expect, snapshot, info } = require("@xieyuheng/test-runner")
const changeCase = require("change-case")
const path = require("path")
const fs = require("fs")

let commands = {}

commands.t = async () => {
  await commands.test_all()
}

commands.test_all = async () => {
  await commands.test_lib()
  await commands.test_impression()
  await commands.test_lang0()
  await commands.test_lang1()
  await commands.test_lang2()
  await commands.test_lang3()
  await commands.test_lang4()
  await commands.test_lang5()
  await commands.test_partech()
}

commands.test_lib = async () => {
  await test("node $file", { file: "lib/**/*.test.js" }, expect.ok)
}

commands.test_impression = async () => {
  await test(
    "node $file",
    { file: "lib/**/*.impression.js" },
    snapshot.out(({ file }) =>
      path.resolve("snapshot", changeCase.paramCase(file) + ".out")
    )
  )
}

commands.test_lang0 = async () => {
  await test(
    "./bin/lang0.js $file",
    { file: "examples/lang0/out/**.cic" },
    snapshot.out(({ file }) => file + ".out")
  )
}

commands.test_lang1 = async () => {
  await test(
    "./bin/lang1.js $file",
    { file: "examples/lang1/out/**.cic" },
    snapshot.out(({ file }) => file + ".out")
  )

  await test(
    "./bin/lang1.js $file",
    { file: "examples/lang1/err/**.cic" },
    snapshot.err(({ file }) => file + ".err")
  )
}

commands.test_lang2 = async () => {
  await test(
    "./bin/lang2.js $file",
    { file: "examples/lang2/out/**.cic" },
    snapshot.out(({ file }) => file + ".out")
  )

  await test(
    "./bin/lang2.js $file",
    { file: "examples/lang2/err/**.cic" },
    snapshot.err(({ file }) => file + ".err")
  )
}

commands.test_lang3 = async () => {
  await test(
    "./bin/lang3.js $file",
    { file: "examples/lang3/out/**.cic" },
    snapshot.out(({ file }) => file + ".out")
  )

  await test(
    "./bin/lang3.js $file",
    { file: "examples/lang3/err/**.cic" },
    snapshot.err(({ file }) => file + ".err")
  )

  await test(
    "./bin/lang3.js run $file",
    { file: "examples/lang3/example-project/play.cic" },
    snapshot.out(({ file }) => file + ".out")
  )

  await test(
    "./bin/lang3.js run $file --verbose",
    { file: "examples/lang3/example-project/play.cic" },
    snapshot.out(({ file }) => file + ".verbose.out")
  )

  await test(
    "./bin/lang3.js run $file --verbose --module-root examples/lang3/example-project",
    { file: "examples/lang3/play.cic" },
    snapshot.out(({ file }) => file + ".verbose.out")
  )

  await test(
    "./bin/lang3.js run $file --module-root examples/lang3/example-project",
    { file: "examples/lang3/play.cic" },
    snapshot.out(({ file }) => file + ".out")
  )
}

commands.test_lang4 = async () => {
  await test(
    "./bin/lang4.js $file",
    { file: "examples/lang4/out/**.jo" },
    snapshot.out(({ file }) => file + ".out")
  )

  await test(
    "./bin/lang4.js $file",
    { file: "examples/lang4/err/**.jo" },
    snapshot.err(({ file }) => file + ".err")
  )
}

commands.test_lang5 = async () => {
  await test(
    "./bin/lang5.js $file",
    { file: "examples/lang5/out/**.jo" },
    snapshot.out(({ file }) => file + ".out")
  )

  await test(
    "./bin/lang5.js $file",
    { file: "examples/lang5/err/**.jo" },
    snapshot.err(({ file }) => file + ".err")
  )
}

commands.test_partech = async () => {
  await commands.test_partech_lex()
  await commands.test_partech_parse()
}

commands.test_partech_lex = async () => {
  await test(
    "./bin/partech.js lex $file --table $file",
    { file: "examples/tables/example.table.js" },
    snapshot.out((_) => "examples/tables/example.tokens.json")
  )

  await test(
    "./bin/partech.js lex $file",
    { file: "examples/tables/example.table.js" },
    snapshot.out((_) => "examples/tables/default.tokens.json")
  )
}

commands.test_partech_parse = async () => {
  const base = "examples/grammars"

  const dirents = await fs.promises.readdir(base, {
    encoding: "utf8",
    withFileTypes: true,
  })

  for (const dirent of dirents) {
    if (dirent.isDirectory()) {
      const name = dirent.name
      const grammar = path.resolve(base, name + ".grammar.js")

      await test(
        `./bin/partech.js parse $file --grammar ${grammar}`,
        { file: `${base}/${name}/**.ok` },
        snapshot.out(({ file }) => file + ".tree")
      )

      await test(
        `./bin/partech.js parse $file --grammar ${grammar} --nocolor`,
        { file: `${base}/${name}/**.oh` },
        snapshot.err(({ file }) => file + ".err")
      )
    }
  }
}

info()

run(commands)
